﻿using SqlSugar;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.SqlSugarCore.SqlSugarFactory;
using Volo.Abp.Threading;
using Volo.Abp.Uow;

namespace Volo.Abp.SqlSugarCore.Uow
{
    public class SqlSugarCoreTransactionApi : ITransactionApi, ISupportsRollback
    {
        public IDbTransaction DbContextTransaction { get; }

        public ISqlSugarClient StarterDbContext { get; }
        public List<ISqlSugarClient> AttendedDbContexts { get; }
        protected ICancellationTokenProvider CancellationTokenProvider { get; }

        public SqlSugarCoreTransactionApi(
            IDbTransaction dbContextTransaction,
            ISqlSugarClient starterDbContext,
            ICancellationTokenProvider cancellationTokenProvider)
        {
            DbContextTransaction = dbContextTransaction;
            StarterDbContext = starterDbContext;
            CancellationTokenProvider = cancellationTokenProvider;
            AttendedDbContexts = new List<ISqlSugarClient>();
        }

        public async Task CommitAsync()
        {
            foreach (var dbContext in AttendedDbContexts)
            {
                if (dbContext.Ado.Connection == DbContextTransaction.Connection)
                {
                    continue; //Relational databases use the shared transaction if they are using the same connection
                }

                dbContext.Ado.CommitTran();
            }

            DbContextTransaction.Commit();
        }

        public void Dispose()
        {
            DbContextTransaction.Dispose();
        }

        public async Task RollbackAsync(CancellationToken cancellationToken)
        {
            foreach (var dbContext in AttendedDbContexts)
            {
                if (dbContext.Ado.Connection == DbContextTransaction.Connection)
                {
                    continue; //Relational databases use the shared transaction if they are using the same connection
                }

                dbContext.Ado.RollbackTran();
            }

            DbContextTransaction.Rollback();
        }
    }
}
